#include "camera.hpp"
#include <iostream>

/**
 * 相机类构造函数
 * 
 * @param index 相机设备索引
 * 初始化相机参数，但不立即打开设备或启动线程
 */
Camera::Camera(int index)
    : camera_index(index), is_running(false), new_frame_available(false) {
    // 初始化成员变量，但不立即打开相机或启动线程
    // is_running和new_frame_available设为false表示初始状态下线程未运行且无可用帧
}

/**
 * 相机类析构函数
 * 
 * 确保在对象销毁前停止采集线程并释放相机资源
 * 防止资源泄漏和悬挂指针问题
 */
Camera::~Camera() {
    stop(); // 确保线程在对象销毁时停止，避免资源泄漏
}

/**
 * 打开相机设备
 * 
 * @return 成功打开返回true，失败返回false
 * 尝试使用OpenCV的VideoCapture打开指定索引的相机设备
 */
bool Camera::open(const AppConfig& config) {
    if (!cap.open(camera_index)) {
        std::cerr << "错误: 无法打开摄像头索引 " << camera_index << "！" << std::endl;
        return false;
    }

    // 根据预设标签设置分辨率
    int width = 640, height = 480; // 默认值
    if (config.resolution_preset == "720p") {
        width = 1280; height = 720;
    } else if (config.resolution_preset == "1080p") {
        width = 1920; height = 1080;
    } else if (config.resolution_preset == "480p") {
        width = 640; height = 480;
    }

    cap.set(cv::CAP_PROP_FRAME_WIDTH, width);
    cap.set(cv::CAP_PROP_FRAME_HEIGHT, height);

    // 获取并打印实际分辨率以供验证
    int actual_width = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_WIDTH));
    int actual_height = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_HEIGHT));
    std::cout << "分辨率设置 -> 请求: " << config.resolution_preset << " (" << width << "x" << height
              << "), 实际: " << actual_width << "x" << actual_height << std::endl;

    return true;
}

/**
 * 启动图像采集线程
 * 
 * 检查相机和线程状态，如果条件满足则创建新线程执行captureLoop函数
 * 使用原子变量is_running作为线程控制标志
 */
void Camera::start() {
    // 检查线程是否已在运行
    if (is_running) {
        std::cout << "相机线程已在运行中。" << std::endl;
        return;
    }
    // 检查相机是否已打开
    if (!cap.isOpened()) {
        std::cerr << "错误: 摄像头未打开，无法启动线程。" << std::endl;
        return;
    }
    // 设置运行标志并启动线程
    is_running = true;
    capture_thread = std::thread(&Camera::captureLoop, this);
    std::cout << "相机采集线程启动成功。" << std::endl;
}

/**
 * 停止图像采集线程
 * 
 * 安全地终止采集线程并释放相机资源
 * 使用exchange原子操作确保线程状态变更的线程安全性
 */
void Camera::stop() {
    // 原子操作：将is_running设为false并返回旧值
    // 如果旧值为false，表示线程已经停止，直接返回
    if (!is_running.exchange(false)) {
        return;
    }

    // 等待线程结束（如果线程可加入）
    if (capture_thread.joinable()) {
        capture_thread.join(); // 阻塞等待线程结束，避免悬挂指针
    }
    // 释放相机资源
    if (cap.isOpened()) {
        cap.release();
    }
    std::cout << "相机线程已停止。" << std::endl;
}

/**
 * 检查相机是否已打开
 * 
 * @return 相机已打开返回true，否则返回false
 * 直接调用OpenCV的VideoCapture::isOpened方法
 */
bool Camera::isOpened() const {
    return cap.isOpened();
}

/**
 * 从共享缓冲区读取最新图像帧
 * 
 * @param frame 用于存储读取到的图像帧的Mat对象引用
 * @return 成功读取返回true，无新帧可读取返回false
 * 使用互斥锁保护共享数据的访问，确保线程安全
 */
bool Camera::read(cv::Mat& frame) {
    // 快速检查是否有新帧可用（无锁检查提高性能）
    if (!new_frame_available) {
        return false; // 没有新帧，立即返回
    }
    // 有新帧可用，加锁访问共享数据
    std::lock_guard<std::mutex> lock(frame_mutex); // RAII方式加锁，确保异常安全
    shared_frame.copyTo(frame); // 深拷贝图像数据，避免共享内存问题
    new_frame_available = false; // 标记已读取，等待新帧
    return true;
}

/**
 * 图像采集循环函数
 * 
 * 在单独的线程中运行，持续从相机获取图像并更新共享缓冲区
 * 使用互斥锁保护共享数据的写入，确保线程安全
 */
void Camera::captureLoop() {
    std::cout << "进入相机采集循环..." << std::endl;
    cv::Mat temp_frame; // 临时帧，用于从相机读取图像
    
    // 只要is_running为true，线程就持续运行
    while (is_running) {
        // 尝试从相机读取一帧图像
        if (!cap.read(temp_frame) || temp_frame.empty()) {
            // 读取失败或帧为空，短暂休眠后重试
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
            continue;
        }
        
        // 使用局部作用域限制锁的范围，减少锁持有时间
        {
            std::lock_guard<std::mutex> lock(frame_mutex); // 加锁保护共享数据
            shared_frame = temp_frame; // 更新共享帧（OpenCV的=操作符会进行深拷贝）
        } // 锁在此处自动释放
        
        // 标记有新帧可用（原子操作，无需加锁）
        new_frame_available = true;
    }
}